package com.spring.theory.aop.advice;

import javax.annotation.PostConstruct;

import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

/**
 * aop 1-4 代理创建的时机
 * 1.无循环依赖：初始化之后
 * 2.有循环依赖：实例创建后，依赖注入前，并暂存于二级缓存
 * <p>
 * 依赖注入与初始化不应该被增强，仍然是原始对象调用
 *
 * @author 24373
 * @version 1.0
 * @date 2024-07-12 16:12
 */
@Slf4j
public class TestAdviceProxy {

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class);
        context.registerBean(AdviceConfig.class);

        context.refresh();
        context.close();

    }

    @Configuration
    static class AdviceConfig {

        @Bean
        public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
            return new AnnotationAwareAspectJAutoProxyCreator();
        }

        @Bean
        public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
            return new AutowiredAnnotationBeanPostProcessor();
        }

        @Bean
        public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
            return new CommonAnnotationBeanPostProcessor();
        }

        @Bean
        public MethodInterceptor methodInterceptor() {
            return new MethodInterceptor() {
                @Override
                public Object invoke(MethodInvocation invocation) throws Throwable {
                    log.info("MethodInterceptor 通知 before");
                    Object result = invocation.proceed();
                    log.info("MethodInterceptor 通知 after");
                    return result;
                }
            };
        }

        @Bean
        public Advisor advisor(MethodInterceptor methodInterceptor) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* test())");
            return new DefaultPointcutAdvisor(pointcut, methodInterceptor);
        }

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }

    }

    static class Bean1 {

        public Bean1() {
            log.info("Bean1的构造器方法运行");
        }

        /**
         * 示例2：添加bean循环依赖；
         * 代理创建时机提前到依赖注入之前
         */
        /*@Autowired
        public void setBean2(Bean2 bean2){
            log.info("Bean1依赖注入Bean2:{}", bean2.getClass());
        }*/
        public Integer test() {
            log.info("Bean1的test主方法运行");
            return 1;
        }

        @PostConstruct
        public void init() {
            log.info("Bean1的init方法运行");
        }
    }

    static class Bean2 {
        public Bean2() {
            log.info("Bean2的构造器方法运行");
        }

        /**
         * 示例1：添加bean依赖注入
         * 代理创建时机提前到bean初始化之后
         */
        @Autowired
        public void setBean1(Bean1 bean1) {
            log.info("Bean2依赖注入Bean1:{}", bean1.getClass());
        }

        @PostConstruct
        public void init() {
            log.info("Bean2的init方法运行");
        }
    }

}
